package com.cloudinnov.utils;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.cloudinnov.utils.model.BxClientModel;
import com.cloudinnov.utils.model.ByteModelBack;

/**
 * TcpClient工具类
 * @ClassName: TcpClientUtil
 * @Description: TODO
 * @author: ningmeng
 * @date: 2016年12月15日 下午3:39:52
 */
public class TcpClientUtil {
	static final Logger _LOG = LoggerFactory.getLogger(TcpClientUtil.class);
	private static final String CAMERA_SPLITTER_LEVEL1 = ",";
	/** 默认端口 可修改 */
	public static int BOARD_PORT = 2929;
	public static final int ERROR_CODE = -1;// 错误
	public static final int PARAMS_ERROR_CODE = 1002;// 参数异常
	public static final int CLIENT_ERROR_CODE = 1004;// 连接异常
	public static final int SYSTEM_ERROR_CODE = 1001;// 系统异常
	public static final int UNKNOWN_STATUS_ERROR = -1;// 未知状态
	public static final int UNKNOWN_STATUS_ERROR_CODE = 1005;// 未知状态
	public static final String PARAMS_ERROR_CODE_MSG = "参数异常";// 参数异常
	public static final String CLIENT_ERROR_CODE_MSG = "连接异常";// 连接异常
	public static final String SYSTEM_ERROR_CODE_MSG = "系统异常";// 系统异常
	public static String CAMERA_SERVER_IP = "10.152.212.2";
	public static int CAMERA_SERVER_PORT = 4999;
	Socket socket = null;
	DataOutputStream bos = null;
	static {
		CAMERA_SERVER_IP = PropertiesUtils.findPropertiesKey("camera.tcp.ip");
		CAMERA_SERVER_PORT = Integer.parseInt(PropertiesUtils.findPropertiesKey("camera.tcp.port"));
	}

	public void ping(BxClientModel model) throws UnknownHostException, IOException {
		Socket socketPing = new Socket(model.getIp(), model.getPort());
		socketPing.setSoTimeout(3000);
		if (socketPing.isConnected()) {
			model.setOK(true);
		}
		socketPing.close();
	}
	public static boolean ping2(String ip, int port) throws UnknownHostException, IOException {
		Socket socketPing = new Socket(ip, port);
		socketPing.setSoTimeout(100);
		boolean status = socketPing.isConnected();
		socketPing.close();
		return status;
	}
	/**
	 * 当返回值是true时，说明host是可用的，false则不可。
	 * @Description: TODO(这里用一句话描述这个方法的作用)
	 * @param @param ipAddress
	 * @param @return
	 * @param @throws Exception 参数
	 * @return boolean 返回类型
	 */
	public static boolean ping(String ipAddress) throws Exception {
		int timeOut = 3000; // 超时应该在3钞以上
		boolean status = InetAddress.getByName(ipAddress).isReachable(timeOut);
		return status;
	}
	public void send(BxClientModel model, int i) throws UnknownHostException, IOException {
		if (socket == null || !socket.isConnected()) {
			socket = new Socket(model.getIp(), model.getPort());
		}
		socket.setSoTimeout(3000);
		OutputStream os = socket.getOutputStream();
		if (bos == null) {
			bos = new DataOutputStream(os);
		}
		bos.write(i);
	}
	/**
	 * 获取情报板数据包的结束位置index
	 * @Description: TODO(这里用一句话描述这个方法的作用)
	 * @param tmp
	 * @return 参数
	 * @return int 返回类型
	 */
	private int getLastEndIndexOfBytes(byte[] tmp) {
		int index = 0;
		for (int i = 0; i < tmp.length; i++) {
			if (tmp[i] == 0x03) {
				index = i;
			}
		}
		return index - 2;// 取消数据校验位和空格
	}
	public String getContent(BxClientModel model) {
		if (CommonUtils.isEmpty(model.getIp())) {
			return PARAMS_ERROR_CODE_MSG;
		}
		try {
			byte[] content = new ByteModelBack().getNowContent();
			for (int i = 0; i < content.length; i++) {
				if (i < 3 || i == content.length - 1) {
					send(model, content[i]);
				} else {
					sendByte1(model, content[i]);
				}
			}
			InputStream is = socket.getInputStream();
			int count = 2048;
			/*
			 * while (count == 0) { count = is.available(); }
			 */
			socket.shutdownOutput();
			byte[] tmp = new byte[count];
			is.read(tmp, 0, tmp.length);
			int newLength = getLastEndIndexOfBytes(tmp);
			if (newLength <= 0) {
				return "";
			}
			byte[] data = Arrays.copyOf(tmp, getLastEndIndexOfBytes(tmp));// 复制数据
			String response = new String(data, "gb2312");
			return response.substring(1, response.length()).trim();
		} catch (UnknownHostException e) {
			_LOG.error("getContent UnknownHostException Is Bad, data:" + JSON.toJSONString(model), e);
			return "";
		} catch (IOException e) {
			_LOG.error("getContent IOException Is Bad, data:" + JSON.toJSONString(model), e);
			return "";
		}
	}
	public String sendContent(BxClientModel model, byte[] byteData) throws SocketException {
		if (CommonUtils.isEmpty(model.getIp())) {
			return PARAMS_ERROR_CODE_MSG;
		}
		String message = null;
		try {
			for (int i = 0; i < byteData.length; i++) {
				if (i < 3 || i == byteData.length - 1) {
					send(model, byteData[i]);
				} else {
					sendByte1(model, byteData[i]);
				}
			}
			InputStream is = socket.getInputStream();
			socket.shutdownOutput();
			byte[] data = new byte[1024];
			is.read(data, 0, data.length);
			int temp = 0;
			if (data[3 + temp] == 0x30) {
				message = CommonUtils.SUCCESS_MSG;
			} else {
				message = CommonUtils.ERROR_MSG;
			}
			is.close();
			bos.close();
			socket.close();
		} catch (UnknownHostException e) {
			_LOG.error("sendContent UnknownHostException Is Bad, data:" + JSON.toJSONString(model), e);
			return SYSTEM_ERROR_CODE_MSG;
		} catch (IOException e) {
			_LOG.error("sendContent IOException Is Bad, data:" + JSON.toJSONString(model), e);
			return SYSTEM_ERROR_CODE_MSG;
		}
		return message;
	}
	public String getFault(BxClientModel model) {
		if (CommonUtils.isEmpty(model.getIp())) {
			return PARAMS_ERROR_CODE_MSG;
		}
		String message = "";
		try {
			byte[] content = new ByteModelBack().getFault();
			for (int i = 0; i < content.length; i++) {
				if (i < 3 || i == content.length - 1) {
					send(model, content[i]);
				} else {
					sendByte1(model, content[i]);
				}
			}
			InputStream is = socket.getInputStream();
			int count = 0;
			while (count == 0) {
				count = is.available();
			}
			socket.shutdownOutput();
			byte[] data = new byte[count];
			is.read(data, 0, data.length - 3);// 取消数据校验位和空格
			int temp = 0;
			for (int i = 0; i < data.length; i++) {
				if (data[3 + temp] == 48) {
					if (data[4 + temp] == 49)
						message = " 光敏部件故障!";
					else if (data[4 + temp] == 50)
						message = " 温度计异常故障!";
					else if (data[4 + temp] == 51)
						message = " 光敏部件故障，温度计异常故障!";
					else if (data[4 + temp] == 52)
						message = " 门开启故障!";
					else if (data[4 + temp] == 53)
						message = " 门开启故障，光敏部件故障!";
					else if (data[4 + temp] == 54)
						message = " 门开启故障，温度计异常故障!";
					else if (data[4 + temp] == 55)
						message = " 门开启故障，温度计异常故障，光敏部件故障!";
					if (data[5 + temp] == 49)
						message = " 单像素管故障!";
					else if (data[5 + temp] == 50)
						message = " 检测系统故障!";
					else if (data[5 + temp] == 51)
						message = " 单像素管故障，检测系统故障!";
					else if (data[5 + temp] == 52)
						message = " 输入220V交流电故障!";
					else if (data[5 + temp] == 53)
						message = " 输入220V交流电故障，单像素管故障!";
					else if (data[5 + temp] == 54)
						message = " 输入220V交流电故障，检测系统故障!";
					else if (data[5 + temp] == 55)
						message = " 输入220V交流电故障，单像素管故障，检测系统故障!";
					else if (data[5 + temp] == 56)
						message = " 防雷器故障!";
					else if (data[5 + temp] == 57)
						message = " 防雷器故障，单像素管故障!";
					else if (data[5 + temp] == 97 || data[5] == 65)
						message = " 防雷器故障，检测系统故障!";
					else if (data[5 + temp] == 98 || data[5] == 66)
						message = " 防雷器故障，检测系统故障，单像素管故障!";
					else if (data[5 + temp] == 99 || data[5] == 67)
						message = " 防雷器故障，输入220V交流电故障!";
					else if (data[5 + temp] == 100 || data[5] == 68)
						message = " 防雷器故障，输入220V交流电故障，单像素管故障!";
					else if (data[5 + temp] == 101 || data[5] == 69)
						message = " 防雷器故障，输入220V交流电故障，检测系统故障!";
					else if (data[5 + temp] == 102 || data[5] == 70)
						message = " 防雷器故障，输入220V交流电故障，检测系统故障，单像素管故障!";
					if (data[6 + temp] == 50)
						message = " 控制器故障!";
					else if (data[6 + temp] == 52)
						message = " 显示模组故障!";
					else if (data[6 + temp] == 54)
						message = " 显示模组故障，控制器故障!";
					else if (data[6 + temp] == 56)
						message = " 显示模组电源故障!";
					else if (data[6 + temp] == 97 || data[5] == 65)
						message = " 显示模组电源故障，控制器故障!";
					else if (data[6 + temp] == 99 || data[5] == 67)
						message = " 显示模组电源故障，显示模组故障!";
					else if (data[6 + temp] == 101 || data[5] == 69)
						message = " 显示模组电源故障，显示模组故障，控制器故障!";
					if (message == "")
						message = " 没有故障！";
				}
			}
			is.close();
			bos.close();
			socket.close();
		} catch (UnknownHostException e) {
			_LOG.error("sendContent UnknownHostException Is Bad, data:" + JSON.toJSONString(model), e);
			return SYSTEM_ERROR_CODE_MSG;
		} catch (IOException e) {
			_LOG.error("sendContent IOException Is Bad, data:" + JSON.toJSONString(model), e);
			return SYSTEM_ERROR_CODE_MSG;
		}
		return message;
	}
	public String sendPresetContent(BxClientModel model) {
		if (CommonUtils.isEmpty(model.getIp())) {
			return PARAMS_ERROR_CODE_MSG;
		}
		String message = null;
		try {
			byte[] content = new ByteModelBack().setPresetContent(model.getProgramName());
			for (int i = 0; i < content.length; i++) {
				if (i < 3 || i == content.length - 1) {
					send(model, content[i]);
				} else {
					sendByte1(model, content[i]);
				}
			}
			InputStream is = socket.getInputStream();
			socket.shutdownOutput();
			byte[] data = new byte[1024];
			is.read(data, 0, data.length);
			int temp = 0;
			if (data[3 + temp] == 0x30) {
				message = CommonUtils.SUCCESS_MSG;
			} else {
				message = CommonUtils.ERROR_MSG;
			}
			is.close();
			bos.close();
			socket.close();
		} catch (UnknownHostException e) {
			_LOG.error("sendPresetContent UnknownHostException Is Bad, data:" + JSON.toJSONString(model), e);
			return SYSTEM_ERROR_CODE_MSG;
		} catch (IOException e) {
			_LOG.error("sendPresetContent IOException Is Bad, data:" + JSON.toJSONString(model), e);
			return SYSTEM_ERROR_CODE_MSG;
		}
		return message;
	}
	/**
	 * 摄像头控制
	 * @Title: controllerCamera
	 * @Description: TODO
	 * @param type 1001 控制
	 * @param content
	 * @return
	 * @return: String
	 */
	public static int controllerCamera(int type, String content) {
		int returnData = 0;
		try {
			// 1.建立客户端socket连接，指定摄像头服务器IP及端口
			Socket socket = new Socket(CAMERA_SERVER_IP, CAMERA_SERVER_PORT);
			socket.setSoTimeout(3000);
			OutputStream os = socket.getOutputStream();
			PrintWriter pw = new PrintWriter(os);
			// 输入流
			InputStream is = socket.getInputStream();
			// 3.利用流按照一定的操作，对socket进行读写操作
			StringBuilder data = new StringBuilder();
			data.append(type + CAMERA_SPLITTER_LEVEL1);
			data.append(content);
			pw.write(data.toString());
			pw.flush();
			socket.shutdownOutput();
			byte[] tmp = new byte[1024];
			is.read(tmp, 0, tmp.length);
			String response = new String(tmp);
			// 4.关闭资源
			is.close();
			pw.close();
			os.close();
			socket.close();
			return Integer.parseInt(response.trim());
		} catch (UnknownHostException e) {
			_LOG.error("UnknownHost Error", e);
			returnData = CLIENT_ERROR_CODE;
		} catch (IOException e) {
			_LOG.error("IOException Error", e);
			returnData = SYSTEM_ERROR_CODE;
		}
		return returnData;
	}

	public static final String PLAY_LIST_TEMPLATE = "item{0} = {1}, {2}, {3}, \\C{4}{5}\\fk{6}\\c{6}{7}{8}{9}\\S{9}{10}\r\n";

	public static void main(String[] args) {
		BxClientModel model = new BxClientModel();
		model.setIp("10.152.214.185");
		model.setPort(2929);
		model.setProgramName("021");
		System.out.println(model.getFontColorRGB().getAlpha());
		System.out.println(new TcpClientUtil().sendPresetContent(model));
		// System.out.println(chineseToString("[Playlist]\r\nItem_No=2\r\nitem0 = 0, 0,
		// 0，额围墙围起围墙围起围墙围起围墙为467321\r\nItem1=500,1,5,\\C008004\\ff2424\\c255000000000\r\n"));
		/*
		 * byte[] b = new byte[8]; // b[0] = 2; b[1] = '0'; b[2] = '0'; b[3] = '9'; b[4] = '8'; b[5]
		 * = '0'; b[6] = '0'; b[7] = '3'; int crc = crcTable(b); // 计算前两位的CRC码
		 */ // 65336
			// System.out.println(crc % 256);
		System.out.println(MessageFormat.format(PLAY_LIST_TEMPLATE, 1, 200, 1));
	}
	public static String chineseToString(String chinese) {
		if (CommonUtils.isEmpty(chinese)) {
			return "";
		} else {
			// 定义StringBuffer
			StringBuffer sb = new StringBuffer();
			// 把传进来的字符串转换成字节数组
			byte[] b = chinese.getBytes();
			byte[] temp = null;
			// 遍历字节数组，把字节数组转换成字符串
			for (int i = 0; i < b.length; i++) {
				temp = new byte[4];
				temp[0] = b[i];
				temp[1] = 0;
				temp[2] = 0;
				temp[3] = 0;
				sb.append(lBytesToInt(temp));
				/*
				 * if (i < b.length - 1) { sb.append("@"); }
				 */
			}
			return sb.toString();
		}
	}
	/**
	 * 将低字节数组转换为int
	 * @param b byte[]
	 * @return int
	 */
	public static int lBytesToInt(byte[] b) {
		int s = 0;
		for (int i = 0; i < 3; i++) {
			if (b[3 - i] >= 0) {
				s = s + b[3 - i];
			} else {
				s = s + 256 + b[3 - i];
			}
			s = s * 256;
		}
		if (b[0] >= 0) {
			s = s + b[0];
		} else {
			s = s + 256 + b[0];
		}
		return s;
	}
	public static int crcTable(byte[] bytes) {
		long c, treat, bcrc;
		int wcrc = 0;
		short i, j;
		for (i = 0; i < bytes.length; i++) {
			c = bytes[i];
			for (j = 0; j < 8; j++) {
				treat = (c & 0x80);
				c <<= 1;
				bcrc = (wcrc >> 8) & 0x80;
				wcrc <<= 1;
				if (treat != bcrc)
					wcrc ^= 0x1021;
			}
		}
		return wcrc;
	}
	void sendByte1(BxClientModel model, int ucBYTE) throws UnknownHostException, IOException {
		switch (ucBYTE) {
			case 2: {
				send(model, 0x1b);
				send(model, 0xe7);
				break;
			}
			case 3: {
				send(model, 0x1b);
				send(model, 0xe8);
				break;
			}
			case 27: {
				send(model, 0x1b);
				send(model, 0x00);
				break;
			}
			default: {
				send(model, ucBYTE);
				break;
			}
		}
	}
	void recDataChange(byte[] data, int wReceiveLength) {
		int i, j;
		for (i = 3; i < wReceiveLength - 1; i++) {
			if (data[i] == 0x1b) {
				switch (data[i + 1]) {
					case (byte) 0xe7:
						data[i] = 0x02;
						for (j = i; j < wReceiveLength - 1; j++) {
							data[j + 1] = data[j + 2];
						}
						break;
					case (byte) 0xe8:
						data[i] = 0x03;
						for (j = i; j < wReceiveLength - 1; j++) {
							data[j + 1] = data[j + 2];
						}
						break;
					case 0x00:
						data[i] = 0x1b;
						for (j = i; j < wReceiveLength - 1; j++) {
							data[j + 1] = data[j + 2];
						}
						break;
				}
				wReceiveLength--;
			}
		}
	}
	public static byte[] deleteAt(byte[] bs, int index) {
		int length = bs.length - 1;
		byte[] ret = new byte[length];
		System.arraycopy(bs, 0, ret, 0, index);
		System.arraycopy(bs, index + 1, ret, index, length - index);
		return ret;
	}
}
